// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stddef.h>
#include <string>
#include <vector>

#include "glog/logging.h"
#include "google/protobuf-expectation/expectation.pb.h"
#include "google/protobuf-expectation/expectation-eval.h"
#include "google/protobuf-expectation/proto-kit-converter.h"
#include "google/protobuf-expectation/proto-kit-generator_test-kit.pb.h"
#include "google/protobuf-expectation/proto-kit-generator_test.pb.h"
#include "google/protobuf/message.h"
#include "google/protobuf/text_format.h"
#include "gtest/gtest.h"

using std::string;
using std::vector;

using google::protobuf::Message;
using google::protobuf::TextFormat;

namespace google {
namespace protobuf_expectation {

class GeneratedProtoKitTest : public ::testing::Test {
 protected:
  bool ConvertAndEvaluate(const Message& expected,
                          const Message& actual) {
    MessageExpectation generic_expectation;
    if (!ConvertToGenericExpectation(actual.GetDescriptor(), expected,
                                     &generic_expectation)) {
      return false;
    }
    vector<EvaluationResult> eval_results;
    if (!Evaluate(generic_expectation, actual, &eval_results)) {
      for (int i = 0; i < eval_results.size(); ++i) {
        LOG(INFO) << "field: " << eval_results[i].field;
        LOG(INFO) << "expected: " << eval_results[i].expected;
        LOG(INFO) << "actual: " << eval_results[i].actual;
        LOG(INFO) << "success: " << eval_results[i].success;
      }
      return false;
    }
    return true;
  }
};

TEST_F(GeneratedProtoKitTest, SingularInt32) {
  google::protobuf_expectation::SingularInt32Kit expected;
  CHECK(TextFormat::ParseFromString(
      "int32_field: < eq: \"123\" >",
      &expected));
  google::protobuf_expectation::SingularInt32 actual;
  actual.set_int32_field(123);
  EXPECT_TRUE(ConvertAndEvaluate(expected, actual));
}

TEST_F(GeneratedProtoKitTest, RepeatedInt32) {
  google::protobuf_expectation::RepeatedInt32Kit expected;
  CHECK(TextFormat::ParseFromString(
      "int32_field: <"
      "  field_size: < eq: \"3\" > "
      "  for_each: < value: < gt: \"0\" > > "
      "  have: < value: < eq: \"456\" > at_index: < eq: \"1\" > > "
      "  do_not_have: < value: < eq: \"666\" > > "
      ">",
      &expected));
  google::protobuf_expectation::RepeatedInt32 actual;
  actual.add_int32_field(123);
  actual.add_int32_field(456);
  actual.add_int32_field(789);
  EXPECT_TRUE(ConvertAndEvaluate(expected, actual));
}

TEST_F(GeneratedProtoKitTest, SingularMessage) {
  google::protobuf_expectation::SingularMessageKit expected;
  CHECK(TextFormat::ParseFromString(
      "message_field: {"
      "  int32_field: < ge: \"0\" and: < le: \"1000\" > > "
      "}",
      &expected));
  google::protobuf_expectation::SingularMessage actual;
  actual.mutable_message_field()->set_int32_field(123);
  EXPECT_TRUE(ConvertAndEvaluate(expected, actual));
}

TEST_F(GeneratedProtoKitTest, RepeatedMessage) {
  google::protobuf_expectation::RepeatedMessageKit expected;
  CHECK(TextFormat::ParseFromString(
      "message_field: {"
      "  field_size: < eq: \"3\" > "
      "  for_each: < int32_field: < gt: \"0\" > > "
      "  have: < int32_field: < eq: \"456\" > at_index: < eq: \"1\" > > "
      "  do_not_have: < int32_field: < eq: \"666\" > > "
      "}",
      &expected));
  google::protobuf_expectation::RepeatedMessage actual;
  actual.add_message_field()->set_int32_field(123);
  actual.add_message_field()->set_int32_field(456);
  actual.add_message_field()->set_int32_field(789);
  EXPECT_TRUE(ConvertAndEvaluate(expected, actual));
}

TEST_F(GeneratedProtoKitTest, NestedMessage) {
  google::protobuf_expectation::NestedMessageKit expected;
  CHECK(TextFormat::ParseFromString(
      "message_field: {"
      "  string_field: < length: < gt: \"0\" and: < le: \"10\" > > > "
      "}",
      &expected));
  google::protobuf_expectation::NestedMessage actual;
  actual.mutable_message_field()->set_string_field("foo");
  EXPECT_TRUE(ConvertAndEvaluate(expected, actual));
}

}  // namespace protobuf_expectation
}  // namespace google
